package com.cy.mall.dao.mongodb;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * @description: mongodb 更新工具
 * @author: Ocean
 * @create: 2018-07-18 16:25
 **/
@Component
@Slf4j
public class MongoDao {

    @Autowired
    private MongoTemplate mongoTemplate;

    public void update(Object obj) {
        Query query = new Query(Criteria.where(id(obj)).is(idValue(obj)));
        Update update = new Update();
        if (getParams(obj).isEmpty()) {
            return;
        }
        getParams(obj).forEach((k, v) -> {
            update.set(k, v);
        });
        mongoTemplate.updateFirst(query, update, obj.getClass());
    }

    private Map<Class, String> idMap = new HashMap<>();

    private String id(Object obj) {
        if (idMap.containsKey(obj.getClass())) {
            return idMap.get(obj.getClass());
        }
        Field[] fileds = obj.getClass().getDeclaredFields();
        Optional<Field> optional = Stream.of(fileds).filter(f -> f.isAnnotationPresent(Id.class)).findFirst();
        Assert.state(optional.isPresent(), "cannot find @Id");
        Field field = optional.get();
        idMap.put(obj.getClass(), field.getName());
        return field.getName();
    }

    private Object idValue(Object obj) {
        String fieldName = id(obj);
        return value(fieldName, obj);
    }

    private Map<String, Object> getParams(Object obj) {
        Map<String, Object> map = new HashMap<>();
        Field[] fileds = obj.getClass().getDeclaredFields();
        Stream.of(fileds).filter(f -> !f.isAnnotationPresent(Id.class)).forEach(f -> {
            Object value = value(f.getName(), obj);
            if (value != null) {
                map.put(f.getName(), value(f.getName(), obj));
            }
        });
        return map;
    }

    private Object value(String fieldName, Object obj) {
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            //设置对象的访问权限，保证对private的属性的访问
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
            log.error("idValue error:", e);
        }
        Assert.state(false, "cannot find value");
        return null;
    }

}
